import {MenuOutlined} from "@ant-design/icons";
import type {DragEndEvent} from "@dnd-kit/core";
import {DndContext} from "@dnd-kit/core";
import {arrayMove, SortableContext, useSortable, verticalListSortingStrategy} from "@dnd-kit/sortable";
import {CSS} from "@dnd-kit/utilities";
import {Table, PaginationProps} from "antd";
import React from "react";

interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
    "data-row-key": string;
}

interface DndTableProps {
    data: any[];
    columns: any[];
    rowKey?: string;
    style?: any;
    setData: (e: any) => any;
    scroll?: any;
    isLine?: boolean;
    pagination?: PaginationProps | boolean | any;
}

//初始头部拖动
const Row = ({children, ...props}: RowProps) => {
    const {attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging} = useSortable({
        id: props["data-row-key"],
    });

    const style: React.CSSProperties = {
        ...props.style,
        transform: CSS.Transform.toString(transform && {...transform, scaleY: 1})?.replace(
            /translate3d\(([^,]+),/,
            "translate3d(0,"
        ),
        transition,
        ...(isDragging ? {position: "relative"} : {}),
    };

    return (
        <tr {...props} ref={setNodeRef} style={style} {...attributes}>
            {React.Children.map(children, child => {
                if ((child as React.ReactElement).key === "sort") {
                    return React.cloneElement(child as React.ReactElement, {
                        children: (
                            <MenuOutlined
                                ref={setActivatorNodeRef}
                                style={{touchAction: "none", cursor: "move"}}
                                {...listeners}
                            />
                        ),
                    });
                }
                return child;
            })}
        </tr>
    );
};

//整行拖动排序 会影响到表格内部按钮的点击事件
const LineRow = ({children, ...props}: RowProps) => {
    const {attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging} = useSortable({
        id: props["data-row-key"],
    });

    const style: React.CSSProperties = {
        ...props.style,
        transform: CSS.Transform.toString(transform && {...transform, scaleY: 1})?.replace(
            /translate3d\(([^,]+),/,
            "translate3d(0,"
        ),
        transition,
        ...(isDragging ? {position: "relative"} : {}),
    };

    return (
        <tr {...props} ref={setNodeRef} style={style} {...attributes}>
            {React.Children.map(children, child => {
                if ((child as React.ReactElement).key === "sort") {
                    return React.cloneElement(child as React.ReactElement, {
                        children: (
                            <MenuOutlined
                                ref={setActivatorNodeRef}
                                style={{touchAction: "none", cursor: "move"}}
                                {...listeners}
                            />
                        ),
                    });
                }
                return child;
            })}
        </tr>
    );
};

const DndTable = ({
    data,
    columns,
    rowKey = "pkId",
    style = {},
    setData,
    scroll,
    isLine = false,
    pagination = false,
}: DndTableProps) => {
    const pageColumns = [
        {
            key: "sort",
            width: 100,
        },
        ...columns,
    ];

    const onDragEnd = ({active, over}: DragEndEvent) => {
        if (active.id !== over?.id) {
            setData((prev: any) => {
                const activeIndex = prev.findIndex((i: any) => i[rowKey] === active.id);
                const overIndex = prev.findIndex((i: any) => i[rowKey] === over?.id);
                const res = arrayMove(prev, activeIndex, overIndex).map((item: any, idx) => ({...item, sort: idx + 1}));
                return res;
            });
        }
    };

    return (
        <DndContext onDragEnd={onDragEnd}>
            <SortableContext items={data.map((i: any) => i[rowKey])} strategy={verticalListSortingStrategy}>
                <Table
                    style={style}
                    scroll={scroll}
                    components={{
                        body: {
                            row: isLine ? LineRow : Row,
                        },
                    }}
                    pagination={pagination}
                    rowKey={rowKey}
                    columns={pageColumns}
                    dataSource={data}
                />
            </SortableContext>
        </DndContext>
    );
};

export default DndTable;
